home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 September / macformat-004.iso / Shareware City / Graphics / VideoToolbox ƒ / VideoToolboxSources / CopyBitsQuicklyOld.c < prev    next >
Encoding:
Text File  |  1994-07-07  |  12.0 KB  |  395 lines  |  [TEXT/KAHL]

  1. /*
  2. CopyBitsQuicklyOld.c
  3. (This is the tried-and-true version used up until June 5, 1994. At that
  4. time I replaced it by a new version that replaces all the assembly code
  5. by portable C code of similar speed. However, if you run into problems 
  6. with the new version you may want to switch back to this old reliable 
  7. version.)
  8.  
  9. CopyBitsQuickly() is a dumb substitute for CopyBits that ignores the color
  10. tables and palettes and leaves the clut alone, simply copying the raw pixels
  11. without any translation. It's for doing animations. (Try the demo Sandstorm.)
  12. Besides copying images, it can also add or multiply them. At one time it copied
  13. much faster than CopyBits did, but the latest timing (under System 7.01), by
  14. TimeVideo, indicates that they are of equal speed.
  15.  
  16. Apple's CopyBits is an Apple Macintosh Toolbox routine for copying images, and
  17. is documented in Inside Macintosh Volumes I,V, and VI. Unlike CopyBits,
  18. CopyBitsQuickly does not cause the Memory Manager to move memory, and thus may
  19. be used in a VBL task.
  20.  
  21. The returned value is nonzero if an error occurred.
  22.  
  23. CopyBitsQuickly supports three modes:
  24.  
  25. srcCopy causes the source to be copied to the destination.
  26.  
  27. addOver causes the source and destination to be added together. Both must have 
  28. 8-bit pixels.  Overflow is ignored.
  29.  
  30. mulOver causes the source and destination to be multiplied, pixel by
  31. pixel. Both must have 8-bit pixels. After multiplication, the product is divided
  32. by 128 and stored in the destination. Overflow is ignored. All the arithmetic
  33. is unsigned.
  34.  
  35. RESTRICTIONS:
  36. It insists that srcBits and dstBits both have the same number of bits/pixel.
  37. It insists that dstRect be the same size as srcRect
  38. It insists that mode==srcCopy, addOver, or new multiplyQuickly.
  39. It insists that maskRgn==NULL
  40. If a Rect extends across multiple screens only as much of the upper-left of the
  41. Rect that's on one device will be used. The rest is clipped off.
  42. If mode is addOver or mulOver then the pixel size must be 8 bits, in both
  43. source and destination.
  44.  
  45. If CopyBitsQuickly detects a violation of any of these restrictions it will return
  46. a nonzero value, indicating that an error occured.
  47.  
  48. NOTE: For highest speed you should choose your srcRectPtr & dstRectPtr so that the
  49. first point moved to and from each row begins at a memory address that is a multiple
  50. of 4 bytes. The effect on speed is substantial, about 25%. 
  51.  
  52. NOTE: If your computer boots in 24-bit mode, as set by the Memory Control Panel,
  53. then the THINK C Debugger will crash if it's activated while you've temporarily
  54. switched into 32-bit mode. So don't put any breakpoints in any section of
  55. code that bracketed by calls to SwapMMUMode() unless your computer booted up in
  56. 32-bit mode. If your computer boots in 32-bit mode then the calls to SwapMMUMode
  57. do nothing, and you can put Debugger breakpoints anywhere.
  58.  
  59. Copyright ©1989-1994 Denis G. Pelli. 
  60.  
  61. HISTORY:
  62. 1/89 dgp    Version 2.0: added support for PixMaps and multiple screens. Added checking.
  63. 6/89 dgp    Version 3.0: now use RectToAddress, which clips to one device.
  64. 10/89 dgp    Version 3.5: Improved resolution from longs to bytes.
  65. 10/89 dgp    Version 4.0: Added new mode: addOver
  66. 3/90  dgp    Version 4.01: Made cosmetic changes:
  67.             renamed srcRect & dstRect to srcRectPtr and dstRectPtr.
  68.             renamed srcAdd to addOver, to conform to CopyBits.
  69.             added a few more comments to explain the initial clipping.
  70. 3/20/90    dgp    made compatible with MPW C.
  71. 4/20/90    dgp    now uses 32-bit addressing only if QD32 is present.
  72. 4/9/91    dgp    v 4.05: changed nudge from short to long, just to be safe
  73. 8/24/91    dgp    Made compatible with THINK C 5.0.
  74. 4/15/92    dgp    Updated CopyBitsQuickly's function header to Standard C style.
  75. 10/5/92 dgp    Dropped support for THINK C 4. Updated the documentation above.
  76. 12/2/92 dgp cosmetic changes
  77. 12/8/92 dgp fixed major gaffe introduced on 12/2/92: "case" prefix was 
  78.             missing in switch statement. This caused CopyBitsQuickly to do nothing. 
  79. 1/31/93    dgp    Added new "multiplyQuickly" mode requested by Josh Solomon. Now 
  80.             insist on 8-bit pixels for both addOver and multiplyQuickly modes.
  81. 2/18/93    js    added mulOver to list of allowed modes. (Oops! - dgp.) Works ok now.
  82. 2/18/93    dgp    Now return int, nonzero if error occurred.
  83. 7/9/93    dgp check for 32-bit addressing capability.
  84. Renamed CopyBitsQuicklyOld.c. Use CopyBitsQuickly.c instead.
  85. 6/14/94    dgp    Copied bug fix from new version: can32 is now computed by calling TrapAvailable(_SwapMMUMode), which 
  86.             returns correct answer even on Macs with dirty ROMs.
  87. */
  88. #include "VideoToolbox.h"
  89.  
  90. typedef unsigned char *UPtr;
  91.  
  92. static void SrcCopyQuickly(UPtr Src,unsigned short srcinc,
  93.     UPtr Dst,unsigned short dstinc,
  94.     unsigned long bytes,unsigned long lines);
  95. static void AddOverQuickly(UPtr Src,unsigned short srcinc,
  96.     UPtr Dst,unsigned short dstinc,
  97.     unsigned long bytes,unsigned long lines);
  98. static void MulOverQuickly(register UPtr Src,register unsigned short srcinc,
  99.     register UPtr Dst,register unsigned short dstinc,
  100.     unsigned long bytes,unsigned long lines);
  101.  
  102. typedef union {
  103.     unsigned long *L;
  104.     unsigned short *W;
  105.     unsigned char *B;
  106. } unsignedPtr;
  107.  
  108. int CopyBitsQuickly(BitMap *srcBits,BitMap *dstBits
  109.     ,Rect *srcRectPtr,Rect *dstRectPtr,int srcMode,RgnHandle maskRgn)
  110. {
  111.     UPtr Src,Dst;
  112.     unsigned short srcinc,dstinc;
  113.     unsigned long lines;
  114.     short srcRowBytes,dstRowBytes;
  115.     short srcPixelSize,dstPixelSize;
  116.     short srcBitsOffset,dstBitsOffset;
  117.     Rect mySrcRect,myDstRect;
  118.     int dx,dy;
  119.     long nudge;
  120.     long bytes;
  121.  
  122.     if(srcMode != srcCopy && srcMode != addOver && srcMode != mulOver) return 1;
  123.     if(maskRgn != NULL) return 1;
  124.  
  125.     /* clip the rect to be copied by the bounds of source and destination */
  126.     mySrcRect=*srcRectPtr;
  127.     myDstRect=*dstRectPtr;
  128.     /* first make sure that srcRect and dstRect are the same size */
  129.     if(mySrcRect.bottom-mySrcRect.top != myDstRect.bottom-myDstRect.top || 
  130.         mySrcRect.right-mySrcRect.left != myDstRect.right-myDstRect.left) 
  131.             return 2;
  132.     dx=myDstRect.left-mySrcRect.left;
  133.     dy=myDstRect.top-mySrcRect.top;
  134.     /* clip myDstRect */
  135.     Dst = RectToAddress((PixMap *)dstBits,&myDstRect,&dstRowBytes,&dstPixelSize,&dstBitsOffset);
  136.  
  137.     /*
  138.     This prevents writing outside the destination.
  139.     The cost is that part of the inside will not be written.
  140.     The problem arises because this routine's code can only write whole bytes,
  141.     and the boundary may be in the middle of a byte. So, rather than writing an
  142.     extra fraction of a byte (outside the destination rect) we leave the byte
  143.     alone and fail to update a small portion inside the destination rect.
  144.     */
  145.     if(dstBitsOffset>0) {
  146.         nudge=(7+dstBitsOffset)/8;
  147.         dstBitsOffset -= nudge*8;
  148.         Dst += nudge;
  149.         myDstRect.left += nudge*8/dstPixelSize;
  150.     }
  151.  
  152.     /* Copy any clipping of myDstRect over to mySrcRect */
  153.     mySrcRect=myDstRect;
  154.     OffsetRect(&mySrcRect,-dx,-dy);
  155.     /* clip mySrcRect */
  156.     Src=RectToAddress((PixMap *)srcBits,&mySrcRect
  157.         ,&srcRowBytes,&srcPixelSize,&srcBitsOffset);
  158.  
  159.     /* Copy any clipping of mySrcRect back to myDstRect */
  160.     myDstRect=mySrcRect;
  161.     OffsetRect(&myDstRect,dx,dy);
  162.     Dst=RectToAddress((PixMap *)dstBits,&myDstRect
  163.         ,&dstRowBytes,&dstPixelSize,&dstBitsOffset);
  164.  
  165.     if(Src==NULL || Dst==NULL) return 3;
  166.     if(srcPixelSize != dstPixelSize) return 4;
  167.     bytes = mySrcRect.right - mySrcRect.left;    /* number of pixels per line */
  168.     bytes *= srcPixelSize;                        /* number of bits per line */
  169.     bytes /= 8;                                    /* number of bytes per line */
  170.     srcinc = srcRowBytes - bytes;        /* offset in bytes to beginning of next line */
  171.     dstinc = dstRowBytes - bytes;
  172.     lines=mySrcRect.bottom - mySrcRect.top;        /* number of lines */
  173.     switch(srcMode){
  174.     case srcCopy:
  175.         SrcCopyQuickly(Src,srcinc,Dst,dstinc,bytes,lines);
  176.         break;
  177.     case addOver:
  178.         if(srcPixelSize!=8)return 5;
  179.         AddOverQuickly(Src,srcinc,Dst,dstinc,bytes,lines);
  180.         break;
  181.     case mulOver:
  182.         if(srcPixelSize!=8)return 5;
  183.         MulOverQuickly(Src,srcinc,Dst,dstinc,bytes,lines);
  184.         break;
  185.     default:
  186.         break;
  187.     }
  188.     return 0;
  189. }
  190.  
  191.     
  192. static void SrcCopyQuickly(UPtr xSrc,unsigned short xsrcinc,
  193.     UPtr xDst,unsigned short xdstinc,
  194.     unsigned long bytes,unsigned long lines)
  195. {
  196.     register unsignedPtr Src,Dst;/* alas, THINK C refuses to place these in registers */
  197.     #if THINK_C
  198.         register unsigned long *SrcR,*DstR;
  199.     #endif
  200.     register unsigned short i,j=lines,longs,srcinc=xsrcinc,dstinc=xdstinc;
  201.     short extra,extra8,extra16;
  202.     char mmumode;
  203.     static Boolean can32,firstTime=1;
  204.  
  205.     if(firstTime){
  206.         can32=TrapAvailable(_SwapMMUMode);
  207.         firstTime=0;
  208.     }
  209.     Src.B=xSrc;
  210.     Dst.B=xDst;
  211.     #if THINK_C
  212.         SrcR=Src.L;
  213.         DstR=Dst.L;
  214.     #endif
  215.     longs = bytes/sizeof(long);                    /* number of longs per line */
  216.     extra = bytes - longs*sizeof(long);            /* residue */
  217.     extra16=extra8=FALSE;
  218.     if(extra >= sizeof(short)) {
  219.         extra16=TRUE;
  220.         extra -= sizeof(short);
  221.     }
  222.     if(extra >= 1) {
  223.         extra8=TRUE;
  224.         extra--;
  225.     }
  226.     mmumode=true32b;
  227.     if(can32)SwapMMUMode(&mmumode);    /* set 32-bit mode */
  228.     /* now choose the fastest possible loop */
  229.     if(srcinc != 0 || dstinc !=0 || extra16 || extra8) {
  230.         #if !THINK_C
  231.             for(;j>0;j--) {
  232.                 for(i=longs;i>0;i--) *Dst.L++ = *Src.L++;
  233.                 if(extra16) *Dst.W++ = *Src.W++;
  234.                 if(extra8) *Dst.B++ = *Src.B++;
  235.                 Src.B += srcinc;
  236.                 Dst.B += dstinc;
  237.             }
  238.         #else
  239.             goto rows1;
  240.     row1:        i=longs;
  241.                 goto cols1;
  242.             asm {
  243.     col1:        MOVE.L    (SrcR)+,(DstR)+
  244.     cols1:        DBRA    i,@col1
  245.             }
  246.                 if(extra16)    asm {MOVE.W    (SrcR)+,(DstR)+};
  247.                 if(extra8)    asm {MOVE.B    (SrcR)+,(DstR)+};
  248.             asm {
  249.                 ADDA.W    srcinc,SrcR
  250.                 ADDA.W    dstinc,DstR
  251.     rows1:        DBRA    j,@row1
  252.             }
  253.         #endif
  254.         if(can32)SwapMMUMode(&mmumode);    /* restore */
  255.         return;
  256.     }
  257.     if(longs*(long)j > 0x10000L) { /* DBRA only uses the lower 16 bits */
  258.         #if !THINK_C
  259.             for(;j>0;j--) {
  260.                 for(i=longs;i>0;i--) *Dst.L++ = *Src.L++;
  261.             }
  262.         #else
  263.             goto rows3;
  264.     row3:        i=longs;
  265.                 goto cols3;
  266.             asm {
  267.     col3:        MOVE.L    (SrcR)+,(DstR)+
  268.     cols3:        DBRA    i,@col3
  269.             }
  270.             asm {
  271.     rows3:    DBRA    j,@row3
  272.             }
  273.         #endif
  274.         if(can32)SwapMMUMode(&mmumode);    /* restore */
  275.         return;
  276.     }
  277.     else {
  278.         j *= longs;
  279.         #if !THINK_C
  280.             for(;j>0;j--) *Dst.L++ = *Src.L++;
  281.         #else
  282.             goto cols4;
  283.             asm {
  284.     col4:        MOVE.L    (SrcR)+,(DstR)+
  285.     cols4:        DBRA    j,@col4
  286.             }
  287.         #endif
  288.         if(can32)SwapMMUMode(&mmumode);    /* restore */
  289.         return;
  290.     }
  291. }
  292.  
  293. static void AddOverQuickly(UPtr xSrc,unsigned short xsrcinc,
  294.     UPtr xDst,unsigned short xdstinc,
  295.     unsigned long xbytes,unsigned long lines)
  296. {
  297.     register UPtr Src=xSrc,Dst=xDst;
  298.     register unsigned long i,j=lines,bytes=xbytes,srcinc=xsrcinc,dstinc=xdstinc;
  299.     char mmumode;
  300.     static Boolean can32,firstTime=1;
  301.  
  302.     if(firstTime){
  303.         can32=TrapAvailable(_SwapMMUMode);
  304.         firstTime=0;
  305.     }
  306.     mmumode=true32b;
  307.     if(can32)SwapMMUMode(&mmumode);    /* set 32-bit mode */
  308.  
  309.     /* now choose the fastest possible loop */
  310.     if(srcinc != 0 || dstinc !=0) {
  311.         #if !THINK_C
  312.             for(;j>0;j--) {
  313.                 for(i=bytes;i>0;i--) *Dst++ += *Src++;
  314.                 Src += srcinc;
  315.                 Dst += dstinc;
  316.             }
  317.         #else
  318.             goto rows1;
  319.     row1:        i=bytes;
  320.                 goto cols1;
  321.             asm {
  322.     col1:        MOVE.B    (Src)+,D0
  323.                 ADD.B    D0,(Dst)+
  324.     cols1:        DBRA    i,@col1
  325.                 ADDA.W    srcinc,Src
  326.                 ADDA.W    dstinc,Dst
  327.     rows1:    DBRA    j,@row1
  328.             }
  329.         #endif
  330.         if(can32)SwapMMUMode(&mmumode);    /* restore */
  331.         return;
  332.     }
  333.     if(bytes*(long)j > 0x10000L) { /* the DBRA only uses the lower 16 bits */
  334.         #if !THINK_C
  335.             for(;j>0;j--) {
  336.                 for(i=bytes;i>0;i--) *Dst++ += *Src++;
  337.             }
  338.         #else
  339.             goto rows3;
  340.     row3:        i=bytes;
  341.                 goto cols3;
  342.             asm {
  343.     col3:        MOVE.B    (Src)+,D0
  344.                 ADD.B    D0,(Dst)+
  345.     cols3:        DBRA    i,@col3
  346.     rows3:    DBRA    j,@row3
  347.             }
  348.         #endif
  349.         if(can32)SwapMMUMode(&mmumode);    /* restore */
  350.         return;
  351.     }
  352.     else {
  353.         j *= bytes;
  354.         #if !THINK_C
  355.             for(;j>0;j--) *Dst++ += *Src++;
  356.         #else
  357.             goto cols4;
  358.             asm {
  359.     col4:        MOVE.B    (Src)+,D0
  360.                 ADD.B    D0,(Dst)+
  361.     cols4:        DBRA    j,@col4
  362.             }
  363.         #endif
  364.         if(can32)SwapMMUMode(&mmumode);    /* restore */
  365.         return;
  366.     }
  367. }
  368.  
  369. // Multiply two unsigned 8-bit pixels, and divide the product by 128.
  370. static void MulOverQuickly(register UPtr Src,register unsigned short srcinc,
  371.     register UPtr Dst,register unsigned short dstinc,
  372.     unsigned long bytes,unsigned long lines)
  373. {
  374.     register unsigned long i,j;
  375.     char mmumode;
  376.     static Boolean can32,firstTime=1;
  377.  
  378.     if(firstTime){
  379.         can32=TrapAvailable(_SwapMMUMode);
  380.         firstTime=0;
  381.     }
  382.     mmumode=true32b;
  383.     if(can32)SwapMMUMode(&mmumode);    /* set 32-bit mode */
  384.     for(j=lines;j>0;j--) {
  385.         for(i=bytes;i>0;i--) {
  386.             *Dst = (unsigned char)((unsigned short)(*Dst)*(unsigned short)(*Src)>>7);
  387.             Src++;
  388.             Dst++;
  389.         }
  390.         Src += srcinc;
  391.         Dst += dstinc;
  392.     }
  393.     if(can32)SwapMMUMode(&mmumode);    /* restore */
  394. }
  395.